import string

# Parse the machine-readable plaintext format from the MRT tool route_btoa
class Update:

    IDLE = 1
    CONNECT = 2
    ACTIVE = 3
    OPENSENT = 4
    OPENCONFIRM = 5
    ESTABLISHED = 6

    states = {
        1:'IDLE',
        2:'CONNECT',
        3:'ACTIVE',
        4:'OPENSENT',
        5:'OPENCONFIRM',
        6:'ESTABLISHED' }

    # Constructor takes a line from the plaintext file
    # Protocol|Time|Type|PeerIP|PeerAS|Prefix|<update dependant>
    # <update dependant>: 
    # ASPATH|Origin|NextHop|LocPref|MED|Community|AtomicAGG|Aggregator||
    def __init__ (self, line):

        # Fields for all updates
        self.protocol = None
        self.time = 0
        self.type = None
        self.peer_ip = None
        self.peer_as = None
        self.prefix = []
        
        # Announcement-specific fields
        self.as_path = []
        self.origin = None
        self.next_hop = None
        self.local_pref = None
        self.med = None
        self.community = None
        self.atomic_agg = None
        self.aggregator = None
        
        # Only for state messages
        self.last_state = None
        self.current_state = None

        line = string.strip(line)
        # Split the line into a list
        data = string.split(line, '|')

        # Updates should be 6 (withdrawal) or 15 (announcement) fields long
        # A - BGP announcement 
        # B - Table dump (Zhen: I am not sure whether this is used or not)
        # W - BGP withdrawal
        # STATE - BGP connection state message
        try:
            assert (data[2] == 'W' and len(data) == 6) \
                  or (data[2] == 'A'  and len(data) == 15 ) \
                  or (data[2] == 'A'  and len(data) == 14 ) \
                  or (data[2] == 'B'  and len(data) == 15 ) \
                  or (data[2] == 'STATE' and len(data) == 7)
        except:
	    print "problem with following data: "
	    print data
	    print "some problem about original data, skip"
            raise

        # We must have these fields for either type
        self.protocol = data[0]
        self.time = int(data[1])    # Timestamps only have a 1 second granularity, so they are int.
        self.type = data[2]
        self.peer_ip = data[3]
        self.peer_as = data[4]

        if len(data) == 7:
            self.last_state = data[5]
            self.current_state = data[6]
            #print '%s - %s - STATE message: %s %s' % (data[1], data[3], data[5], data[6])

        if len(data) == 6:
            self.prefix = string.split(data[5], ' ')    # A list of prefixes

        # Update is 15 fields
        if len(data) == 15:
            self.prefix = string.split(data[5], ' ')    # A list of prefixes
            self.as_path = data[6]
            #self.as_path = string.split(data[6], ' ')   # A list of ASes
            #self.origin = data[7]
            #self.next_hop = data[8]
            #self.local_pref = data[9]
            #self.med = data[10]
            #self.community = data[11]
            #self.atomic_agg = data[12]
            #self.aggregator = data[13]

    # Function to convert the update to a string
    # Implicitly called by something like: print update
    # Basically we just join the fields back together like it was originally
    def __str__ (self):

        # All updates have these 5
        s = string.join([self.protocol, str(self.time), self.type,
                self.peer_ip, self.peer_as], '|')
        
        # State update
        if self.type == 'STATE':
            s = string.join([s, self.last_state, self.current_state], '|')

        elif self.type == 'W':
            s = string.join([s, string.join(self.prefix)], '|')

        # Announcements have more
        elif self.type == 'A' or self.type == 'B':
            s = string.join([s, string.join(self.prefix), 
                string.join(self.as_path), self.origin, 
                self.next_hop, self.local_pref, self.med, self.community, 
                self.atomic_agg, self.aggregator, ''], '|')

        return s

    def basicStr(self):
	s = string.join([str(self.time), self.type, self.peer_ip, self.peer_as], '|')
	if self.type == 'A':
	    s = string.join([s, string.join(self.prefix), string.join(self.as_path)], '|')
	elif self.type == 'W':
	    s = string.join([s, string.join(self.prefix)], '|')
	return s 
